#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include "data_type.h"
#include "alloc.h"
#include "memfunc.h"
#include "json.h"
#include "struct_deal.h"
#include "crypto_func.h"
#include "basefunc.h"
#include "memdb.h"
#include "message.h"
#include "connector.h"
#include "ex_module.h"
#include "channel.h"
#include "sys_func.h"

//#include "app_struct.h"
#include "tpm2_value.h"
#include "tpm2_base_structs.h"
#include "tpm2_structure.h"


#include "tpm2_global.h"
#include "tpm2_command.h"

#include "tpm2_channel.h"

#define MAX_LINE_LEN 1024

static unsigned char Buf[DIGEST_SIZE*128];
static BYTE * ReadBuf=Buf;
static int readbuf_len=0;
static BYTE * WriteBuf=Buf+DIGEST_SIZE*64;
static int write_len=0;

// static int index = 0;
static char errorbuf[1024];
static unsigned char sendbuf[4096];
static CHANNEL * tpm2_channel;
static void * extend_template;

int tcm_get_type_bytag(int tag)
{
	int ret;
	switch(tag)
	{
		case TPM_ST_NO_SESSIONS:
			ret=TYPE(TPM2_IN);
			break;
		case TPM_ST_SESSIONS:
			ret=TYPE(TPM2_IN);
			break;
		default:
			ret= -EINVAL;
	}
	return ret;
}

int tpm2_channel_init(void * sub_proc,void * para)
{
    int ret;
    struct tpm2_channel_init_para * init_para=para;
    if(para==NULL)
	return -EINVAL;
    tpm2_channel=channel_find(init_para->channel_name);

    if(tpm2_channel==NULL)
	return -EINVAL;	
    extend_template=memdb_get_template(TYPE_PAIR(TPM2_EXTERNAL,INPUT_COMMAND)) ;
    if(extend_template==NULL)
    {
    	printf("load extend template error!\n");
    	return -EINVAL;
    }

    return 0;
}

int tpm2_channel_start(void * sub_proc,void * para)
{
    int ret = 0, len = 0, i = 0, j = 0;
    int rc = 0;


    while(1)
    {
        usleep(time_val.tv_usec/10);
		ret=channel_read(tpm2_channel,ReadBuf+readbuf_len,DIGEST_SIZE*32-readbuf_len);
		if(ret<0)
			return ret;
		if(ret>0)
		{
			readbuf_len+=ret;
	
		//get the head of the template

 	        RECORD(TPM2_EXTERNAL,INPUT_COMMAND) *output_data;

        	output_data = Talloc0(sizeof(*output_data)) ;
        	ret = blob_2_struct(ReadBuf, output_data,extend_template) ;
			int offset=ret;
			int type,subtype;
	

			switch(output_data->tag)
			{
				case TPM_ST_NO_SESSIONS:
				case TPM_ST_SESSIONS:
				{ 
					type=TYPE(TPM2_IN);
					subtype=output_data->commandCode;

                	void * command_template = memdb_get_template(type,subtype) ;
					//Get the entire command template
                	if(command_template == NULL)
                	{
                		printf("tpm2_channel:can't solve command %x %x!\n",type,subtype);
               		}	
               		else 
               		{
                		void * Extend_input = Talloc0(struct_size(command_template));
                    	ret = blob_2_struct(ReadBuf, Extend_input, command_template);
						if((ret<0)|| (ret>readbuf_len))
						{
							printf("solve command failed!\n");
							return -EINVAL;
						}
				//  clear the read data
			
						Memcpy(ReadBuf,ReadBuf+ret,readbuf_len-ret);
						readbuf_len-=ret;

                    	void * send_msg = message_create(type,subtype,NULL);
                    	if(send_msg == NULL)
                    		return -EINVAL;
                    	message_add_record(send_msg, Extend_input);
                    	ret=ex_module_sendmsg(sub_proc,send_msg);
               		}
					break;
				}
				default:
					printf("error vtcm command head format!\n");
			}
		}	
					
		void *message_box ;

    	if((ex_module_recvmsg(sub_proc,&message_box)>=0)
			&&(message_box!=NULL))
    	{
	    	int type;
	    	int subtype;
	    	type=message_get_type(message_box);
	    	subtype=message_get_subtype(message_box);

        	MSG_HEAD * message_head;
        	message_head=message_get_head(message_box);
	    	MSG_EXPAND * msg_expand;
	    	BYTE * cmd_buf;
	    	UINT16 tag;
	
        	void * record;
        	void * out_msg_template=memdb_get_template(message_head->record_type,message_head->record_subtype);
	    	if(out_msg_template==NULL)
	   	 	{
				printf("get record (%d %d)'s template error!\n",message_head->record_type,message_head->record_subtype);
		  		return -EINVAL;
	    	}	
        	int  blob_size;
	    	int  offset;

	    	offset=0;
	    	
         	record=Talloc0(struct_size(out_msg_template));

         	ret = message_get_record(message_box,&record,0);
	
			cmd_buf=sendbuf;

         	blob_size=struct_2_blob(record, cmd_buf,out_msg_template);

	    	*(int *)(cmd_buf+2)=htonl(blob_size);
        	if(offset>0)
	   		{
		   		*(int *)(sendbuf+2)=htonl(offset+blob_size);
	   		}	

	    	int len=channel_write(tpm2_channel,sendbuf,blob_size+offset);
        	if (len != blob_size+offset)
            	print_cubeerr("tpm2_channel write failed!\n");
        }
    }
    return 0;
}
